src/pages/cellar/[short_id].astro 2.8 K raw
1
---
2
export const prerender = false;
3
4
import PageLayout from "@/layouts/Base.astro";
5
6
const { short_id } = Astro.params;
7
const CELLAR_API_URL =
8
	import.meta.env.CELLAR_API_URL ?? "https://cellar.stevedylan.dev";
9
10
let wine: any = null;
11
let fetchError: string | null = null;
12
try {
13
	const res = await fetch(`${CELLAR_API_URL}/api/wines/${short_id}`);
14
	if (res.status === 404) {
15
		return Astro.redirect("/404");
16
	} else if (!res.ok) {
17
		fetchError = `API returned ${res.status}`;
18
	} else {
19
		wine = await res.json();
20
	}
21
} catch (e) {
22
	fetchError = e instanceof Error ? e.message : "Failed to reach cellar API";
23
}
24
25
const meta = {
26
	title: wine?.name ?? "Wine",
27
	description: wine ? `${wine.origin} ยท ${wine.grape}` : "",
28
};
29
---
30
31
<PageLayout meta={meta}>
32
	<div class="flex flex-col gap-6 w-full pb-16">
33
34
		{fetchError ? (
35
			<p class="text-red-400 text-sm">Could not load wine: {fetchError}</p>
36
		) : wine && (
37
			<>
38
				<h1 class="title" style="letter-spacing:-0.5px">{wine.name}</h1>
39
40
				<div class="grid grid-cols-2 gap-6 items-center wine-detail-top">
41
					{wine.has_image && (
42
						<div class="w-full">
43
							<img
44
								src={`${CELLAR_API_URL}/wines/${wine.short_id}/image`}
45
								alt={`Bottle photo of ${wine.name}`}
46
								class="w-full object-cover rounded wine-image"
47
								loading="eager"
48
							/>
49
						</div>
50
					)}
51
					{!wine.wishlist && (
52
						<div class="flex flex-col items-center gap-4 p-3">
53
							<img
54
								src={`${CELLAR_API_URL}/api/wines/${wine.short_id}/pentagon.svg`}
55
								alt={`Pentagon chart of taste profile for ${wine.name}`}
56
								width="250"
57
								height="250"
58
								loading="eager"
59
							/>
60
							<img
61
								src={`${CELLAR_API_URL}/api/wines/${wine.short_id}/bars.svg`}
62
								alt={`Bar chart of appearance and nose for ${wine.name}`}
63
								width="250"
64
								loading="eager"
65
							/>
66
						</div>
67
					)}
68
				</div>
69
70
				<div class="flex flex-col gap-1">
71
					{wine.origin && (
72
						<div class="flex gap-3 text-sm">
73
							<span class="text-xs opacity-50">origin</span>
74
							<span>{wine.origin}</span>
75
						</div>
76
					)}
77
					{wine.grape && (
78
						<div class="flex gap-3 text-sm">
79
							<span class="text-xs opacity-50">grape</span>
80
							<span>{wine.grape}</span>
81
						</div>
82
					)}
83
				</div>
84
85
				{wine.notes && (
86
					<div class="flex flex-col gap-1">
87
						<span class="text-xs opacity-50">notes</span>
88
						<p class="whitespace-pre-wrap">{wine.notes}</p>
89
					</div>
90
				)}
91
92
				{wine.background && (
93
					<div class="flex flex-col gap-1">
94
						<span class="text-xs opacity-50">background</span>
95
						<p class="whitespace-pre-wrap">{wine.background}</p>
96
					</div>
97
				)}
98
			</>
99
		)}
100
	</div>
101
  		<a href="/cellar" class="text-sm">โ† cellar</a>
102
103
</PageLayout>
104
105
<style>
106
	@media (max-width: 480px) {
107
		.wine-detail-top {
108
			grid-template-columns: 1fr;
109
		}
110
		.wine-image {
111
			max-height: none;
112
			width: 100%;
113
		}
114
	}
115
</style>